module Project3(SW,KEY,LEDR,LEDG,HEX0,HEX1,HEX2,HEX3,CLOCK_50);
	input  [9:0] SW;
	input  [3:0] KEY;
	input  CLOCK_50;
	output [9:0] LEDR;
	output [7:0] LEDG;
	output [6:0] HEX0,HEX1,HEX2,HEX3;

	parameter DBITS    =32;
	parameter INSTSIZE =32'd4;
	parameter INSTBITS =32;
	parameter STARTPC  =32'h20;
	parameter REGNOBITS=5;
	parameter IMMBITS  =16;
	parameter ADDRKEY  =32'hFFFFFF00;
	parameter ADDRKDATA=32'hFFFFFF00;
	parameter ADDRKCTRL=32'hFFFFFF04;
	parameter ADDRSW   =32'hFFFFFF10;
	parameter ADDRSDATA=32'hFFFFFF10;
	parameter ADDRSCTRL=32'hFFFFFF14;
	parameter ADDRHEX =32'hFFFFFF80;
	parameter ADDRHBLNK=32'hFFFFFF84;
	parameter ADDRLEDR=32'hFFFFFF90;
	parameter ADDRLEDG=32'hFFFFFFA0;
	parameter IMEMINITFILE="Test2new.mif";
	parameter IMEMADDRBITS=13;
	parameter IMEMWORDBITS=2;
	parameter IMEMWORDS=2048;
	parameter DMEMADDRBITS=13;
	parameter DMEMWORDBITS=2;
	parameter DMEMWORDS=2048;

	parameter LOGICBITS = 2;
	parameter LOGIC_AND = 2'd0;
	parameter LOGIC_OR  = 2'd1;
	parameter LOGIC_XOR = 2'd2;
 
	parameter OP1_ALUR=6'o00;
	parameter OP1_ANDI=6'o01;
	parameter OP1_ORI =6'o02;
	parameter OP1_HI  =6'o03;
	parameter OP1_ADDI=6'o04;
	parameter OP1_LW  =6'o20;
	parameter OP1_SW  =6'o21;
	parameter OP1_JAL =6'o40;
	parameter OP1_BEQ =6'o41;
	parameter OP1_BNE =6'o45;
 
	parameter OP2_AND =6'o11;
	parameter OP2_OR  =6'o12;
	parameter OP2_XOR =6'o13;
	parameter OP2_NAND=6'o15;
	parameter OP2_NOR =6'o16;
	parameter OP2_NXOR=6'o17;
	parameter OP2_ADD =6'o20;
	parameter OP2_SUB =6'o21;
	parameter OP2_EQ  =6'o41;
	parameter OP2_LT  =6'o42;
	parameter OP2_LE  =6'o43;
	parameter OP2_NE  =6'o45;
	parameter OP2_GE  =6'o46;
	parameter OP2_GT  =6'o47;
	// This is not a valid opcode2 value, but it is a valid ALUfunc value
	parameter OP2_LOHI=6'o77;
	
	parameter BCOND_EQ=1'b0;
	parameter BCOND_NE=1'b1;
	
	parameter CLOCKS_PER_MS=83300;
	parameter CLOCKS_PER_10MS=833000;

	wire clk,lock;
	Pll pll(.inclk0(CLOCK_50),.c0 (clk),.locked(lock));
	wire reset=!lock;
	
	/*-----------------------------
	 * FETCH
	 *-----------------------------*/
	reg [(DBITS-1):0] PC_F;
	wire [(DBITS-1):0] pcplus_F=PC_F+32'd4;
	
	// branch prediction
	wire [(DBITS-1):0] pcpred_F = (PC_F==bpred_from) ? bpred_target : pcplus_F;
	reg [(DBITS-1):0] bpred_target, bpred_from;
	
	// PC determination
	always @(posedge clk) begin
		if(reset)
			PC_F<=32'h20;
		else if(mispred_M) begin
			PC_F<=pcgood_M;
			bpred_target <= pcgood_M;
			bpred_from <= PC_M;
		end
		else if(!stall_F)
			PC_F<=pcpred_F;
	end
	
  // Instruction fetch
  (* ram_init_file = IMEMINITFILE *)
  reg [(DBITS-1):0] imem[(IMEMWORDS-1):0];
  wire [(DBITS-1):0] inst_F=imem[PC_F[(IMEMADDRBITS-1):IMEMWORDBITS]];

	// F2D flip-flops
	reg [(DBITS-1):0] inst_D,PC_D,pcplus_D,pcpred_D;
	reg flushed_D;
	wire flush_F = flush_D;

	always @(posedge clk) begin
		
		if(lock) begin
			if(flush_F)
				{inst_D,flushed_D}<=
				{ 32'b0,     1'b1};
			else if(!stall_D)
				{inst_D,flushed_D}<=
				{inst_F,     1'b0};
		end
		else
			flushed_D <= 1'b1;
		
		if(flush_F)
			{PC_D ,pcplus_D,pcpred_D}<=
			{32'b0,   32'b0,   32'b0};
			//{IW_NOP,pcgood_B,pcgood_B};
		else if(!stall_D)
			{PC_D,pcplus_D,pcpred_D}<=
			{PC_F,pcplus_F,pcpred_F};
	end

	/*-----------------------------
	 * DECODE
	 *-----------------------------*/
	// nice names for IR signals
	wire [5:0] opcode1_D				= inst_D[31:26];
	wire [(REGNOBITS-1):0] rx_D 	= inst_D[25:21];
	wire [(REGNOBITS-1):0] ry_D 	= inst_D[20:16];
	wire [(REGNOBITS-1):0] rz_D 	= inst_D[15:11];
	wire [5:0] opcode2_D				= inst_D[ 5: 0];
	wire [(IMMBITS-1):0] imm_D		= inst_D[(IMMBITS-1): 0];
	
	// registers for decoded signals
	reg rdreg1_D,rdreg2_D,aluimm_D,arithsub_D,sellogic_D,logicneg_D,btest_D,iinst_D,isjump_D,complt_D,compeq_D,bcond_D;
	reg sinst_D,reti_D;
	reg selpcplus_D,selarith_D,selcomp_D,sellohi_D,selmem_D,selsreg_D;
	reg wrmem_D,wrreg_D,wsreg_D;
	reg [(REGNOBITS-1):0] wregno_D;
	reg [(LOGICBITS-1):0] logicop_D;
	
	// decode instruction and generate signals
	wire flush_D = flush_A;
	always @(inst_D or opcode1_D or opcode2_D or rx_D or ry_D or rz_D or flush_D) begin
		// TODO: check these default values
		{rdreg1_D,rdreg2_D,aluimm_D,arithsub_D,logicneg_D,btest_D,iinst_D,isjump_D,complt_D,compeq_D}=
		{    1'b0,    1'b0,    1'b0,      1'b0,      1'b0,   1'b0,   1'b0,    1'b0,    1'b0,    1'b0};
		{selpcplus_D,selarith_D,sellogic_D,selcomp_D,sellohi_D,selmem_D,selsreg_D}=
		{       1'b0,      1'b0,      1'b0,     1'b0,     1'b0,    1'b0,     1'b0};
		{wrmem_D,wrreg_D,wsreg_D}=
		{   1'b0,   1'b0,   1'b0};
		bcond_D = 1'bX;
		wregno_D = {REGNOBITS{1'bX}};
		logicop_D = {LOGICBITS{1'bX}};
		case(opcode1_D)
			OP1_ALUR: begin
				case(opcode2_D)
					OP2_ADD:
						{rdreg1_D,rdreg2_D,aluimm_D,selarith_D,arithsub_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1,      1'b0,    rz_D,   1'b1};
					OP2_SUB:
						{rdreg1_D,rdreg2_D,aluimm_D,selarith_D,arithsub_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1,      1'b1,    rz_D,   1'b1};
					OP2_AND:
						{rdreg1_D,rdreg2_D,aluimm_D,sellogic_D,logicop_D,logicneg_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1,LOGIC_AND,      1'b0,    rz_D,   1'b1};
					OP2_OR:
						{rdreg1_D,rdreg2_D,aluimm_D,sellogic_D,logicop_D,logicneg_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1, LOGIC_OR,      1'b0,    rz_D,   1'b1};
					OP2_XOR:
						{rdreg1_D,rdreg2_D,aluimm_D,sellogic_D,logicop_D,logicneg_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1,LOGIC_XOR,      1'b0,    rz_D,   1'b1};
					OP2_NAND:
						{rdreg1_D,rdreg2_D,aluimm_D,sellogic_D,logicop_D,logicneg_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1,LOGIC_AND,      1'b1,    rz_D,   1'b1};
					OP2_NOR:
						{rdreg1_D,rdreg2_D,aluimm_D,sellogic_D,logicop_D,logicneg_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1, LOGIC_OR,      1'b1,    rz_D,   1'b1};
					OP2_NXOR:
						{rdreg1_D,rdreg2_D,aluimm_D,sellogic_D,logicop_D,logicneg_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,    1'b0,      1'b1,LOGIC_XOR,      1'b1,    rz_D,   1'b1};
					OP2_EQ:
						{rdreg1_D,rdreg2_D,selcomp_D,compeq_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,     1'b1,    1'b1,    rz_D,   1'b1};
					OP2_LT:
						{rdreg1_D,rdreg2_D,selcomp_D,complt_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,     1'b1,    1'b1,    rz_D,   1'b1};
					OP2_LE:
						{rdreg1_D,rdreg2_D,selcomp_D,compeq_D,complt_D,wregno_D,wrreg_D}=
						{    1'b1,    1'b1,     1'b1,    1'b1,    1'b1,    rz_D,   1'b1};
					OP2_NE:
						{rdreg1_D,rdreg2_D,selcomp_D,compeq_D,wregno_D,wrreg_D,logicneg_D}=
						{    1'b1,    1'b1,     1'b1,    1'b1,    rz_D,   1'b1,      1'b1};
					OP2_GE:
						{rdreg1_D,rdreg2_D,selcomp_D,complt_D,wregno_D,wrreg_D,logicneg_D}=
						{    1'b1,    1'b1,     1'b1,    1'b1,    rz_D,   1'b1,      1'b1};
					OP2_GT:
						{rdreg1_D,rdreg2_D,selcomp_D,compeq_D,complt_D,wregno_D,wrreg_D,logicneg_D}=
						{    1'b1,    1'b1,     1'b1,    1'b1,    1'b1,    rz_D,   1'b1,      1'b1};
					default:
						iinst_D=1'b1;
				endcase
			end
			OP1_ADDI:
				{rdreg1_D,selarith_D,arithsub_D,aluimm_D,wregno_D,wrreg_D}=
				{    1'b1,      1'b1,      1'b0,    1'b1,    ry_D,   1'b1};
			OP1_ANDI:
				{rdreg1_D,sellogic_D,aluimm_D,wregno_D,wrreg_D,logicop_D}=
				{    1'b1,      1'b1,    1'b1,    ry_D,   1'b1,LOGIC_AND};
			OP1_ORI:
				{rdreg1_D,sellogic_D,aluimm_D,wregno_D,wrreg_D,logicop_D}=
				{    1'b1,      1'b1,    1'b1,    ry_D,   1'b1, LOGIC_OR};
			OP1_HI:
				{rdreg1_D,sellohi_D,aluimm_D,wregno_D,wrreg_D}=
				{    1'b1,     1'b1,    1'b1,    ry_D,   1'b1};
			OP1_LW:
				{rdreg1_D,aluimm_D,selmem_D,wrreg_D,wregno_D}=
				{    1'b1,    1'b1,    1'b1,   1'b1,     ry_D};
			OP1_SW:
				{rdreg1_D,rdreg2_D,aluimm_D,wrmem_D}=
				{    1'b1,    1'b1,    1'b1,   1'b1};
			OP1_JAL:
				{rdreg1_D,isjump_D,selpcplus_D,wrreg_D,wregno_D}=
				{    1'b1,    1'b1,       1'b1,   1'b1,    ry_D};
			OP1_BEQ:
				{rdreg1_D,rdreg2_D,btest_D, bcond_D}=
				{    1'b1,    1'b1,   1'b1,BCOND_EQ};
			OP1_BNE:
				{rdreg1_D,rdreg2_D,btest_D, bcond_D}=
				{    1'b1,    1'b1,   1'b1,BCOND_NE};
			default:
				iinst_D=1'b1;
		endcase
	end
	wire gotresultALU_D = !selmem_D && !selsreg_D;

	// create register file
	(* ramstyle="logic" *)
	reg [(DBITS-1):0] regs[31:0];
	wire [(REGNOBITS-1):0] rregno1_D=rx_D, rregno2_D=ry_D;
	
	// read from reg file
	wire [(DBITS-1):0] regout1_D = regs[rregno1_D];
	wire [(DBITS-1):0] regout2_D = regs[rregno2_D];
	
	// forwarding logic
	wire forw1A_D=wrreg_A&&(rregno1_D==wregno_A);
	wire forw2A_D=wrreg_A&&(rregno2_D==wregno_A);
	wire stallA_D=((forw1A_D&&rdreg1_D)||(forw2A_D&&rdreg2_D))&&(!gotresult_A);
	wire forw1M_D=wrreg_M&&(rregno1_D==wregno_M);//TODO what if ALU instruction is in MEM stage?
	wire forw2M_D=wrreg_M&&(rregno2_D==wregno_M);
	wire forw1W_D=wrreg_W&&(rregno1_D==wregno_W);
	wire forw2W_D=wrreg_W&&(rregno2_D==wregno_W);

	// decide on what register output should be
	wire [(DBITS-1):0] regval1_D=forw1A_D?result_A:
											forw1M_D?result_M:
											forw1W_D?result_W:
											regout1_D;
	wire [(DBITS-1):0] regval2_D=forw2A_D?result_A:
											forw2M_D?result_M:
											forw2W_D?result_W:
											regout2_D;
	wire stall_D=stallA_D;
	wire stall_F=stall_D;
	
	// compute btarg, jtarg
	wire [(DBITS-1):0] bimm_D={{(DBITS-IMMBITS-2){imm_D[IMMBITS-1]}},imm_D,2'b00}; // TODO: is this correctly shifted?
	wire [(DBITS-1):0] btarg_D=pcplus_D+bimm_D;
	wire [(DBITS-1):0] jtarg_D=regval1_D+bimm_D;
	
	// D2A flip-flops
	reg aluimm_A,logicneg_A,arithsub_A,complt_A,compeq_A;
	reg selpcplus_A,sellogic_A,selarith_A,selcomp_A,sellohi_A,selmem_A,selsreg_A;
	reg wrmem_A,wsreg_A,reti_A,wrreg_A,iinst_A,sinst_A,flushed_A,btest_A,isjump_A;
	reg [(DBITS-1):0] regval1_A,regval2_A,PC_A,btarg_A,jtarg_A,pcplus_A,bcond_A,bimm_A,pcpred_A;
	reg [(REGNOBITS-1):0] rregno1_A,wregno_A;
	reg [(IMMBITS-1):0] imm_A;
	reg [(LOGICBITS-1):0] logicop_A;
	always @(posedge clk) begin
		if(reset) begin
			flushed_A <= 1'b1;
			{btarg_A,jtarg_A,isjump_A,btest_A}<=
			{  32'b0,  32'b0,    1'b0,   1'b0};
		end
		gotresult_A <= gotresultALU_D;
		{regval1_A,regval2_A,imm_A,aluimm_A}<=
		{regval1_D,regval2_D,imm_D,aluimm_D};
		{logicop_A,logicneg_A,arithsub_A,complt_A,compeq_A}<=
		{logicop_D,logicneg_D,arithsub_D,complt_D,compeq_D};
		{selpcplus_A,sellogic_A,selarith_A,selcomp_A,selmem_A,selsreg_A}<=
		{selpcplus_D,sellogic_D,selarith_D,selcomp_D,selmem_D,selsreg_D};
		{wrmem_A,rregno1_A,wsreg_A,reti_A,wrreg_A,wregno_A}<=
		{wrmem_D,rregno1_D,wsreg_D,reti_D,wrreg_D,wregno_D};
		{iinst_A,sinst_A,flushed_A,PC_A,pcpred_A}<=
		{iinst_D,sinst_D,flushed_D,PC_D,pcpred_D};
		//{btarg_A,jtarg_A,btest_A,isjump_A,pcplus_A,bcond_A,bimm_A}<=
		//{btarg_D,jtarg_D,btest_D,isjump_D,pcplus_D,bcond_D,bimm_D};
		bimm_A <= bimm_D;
		bcond_A <= bcond_D;
		isjump_A <= isjump_D;
		btest_A <= btest_D;
		jtarg_A <= jtarg_D;
		btarg_A <= btarg_D;
		pcplus_A <= pcplus_D;
		sellohi_A <= sellohi_D;
		if(flush_D||stall_D)
			{wrmem_A,wsreg_A,reti_A,wrreg_A,iinst_A,sinst_A,flushed_A}<=
			{   1'b0,   1'b0,  1'b0,   1'b0,   1'b0,   1'b0,     1'b1};
	end

	/*-----------------------------
	 * ALU
	 *-----------------------------*/
	
	wire flush_A = flush_M;
	reg gotresult_A;
	wire signed [(DBITS-1):0] aluout_A;
	wire [(DBITS-1):0] sxtimm_A = {{(DBITS-IMMBITS){imm_A[IMMBITS-1]}},imm_A};
	wire signed [(DBITS-1):0] aluin1 = regval1_A;
	wire signed [(DBITS-1):0] aluin2 = aluimm_A?sxtimm_A:regval2_A;
	
	// results for each operation
	wire [(DBITS-1):0] resarith_A=aluin1+(aluin2^{DBITS{arithsub_A}})+arithsub_A; // 2's comp
	wire rescomp_A=(((aluin1<aluin2)&&complt_A)|((aluin1==aluin2)&&compeq_A))^logicneg_A;
	wire [(DBITS-1):0] vallogic_A=
		(logicop_A==LOGIC_AND)?(aluin1&aluin2):
		(logicop_A==LOGIC_OR )?(aluin1|aluin2):
		(logicop_A==LOGIC_XOR)?(aluin1^aluin2):
		{DBITS{1'bX}};
	wire [(DBITS-1):0] reslogic_A={DBITS{logicneg_A}}^vallogic_A;
	wire [(DBITS-1):0] reslohi_A ={aluin2[15:0],aluin1[15:0]};
	
	// select the correct output for ALU
	wire [(DBITS-1):0] result_A =
		sellogic_A ? reslogic_A :
		selarith_A ? resarith_A :
		selcomp_A  ? rescomp_A :
		sellohi_A  ? reslohi_A :
		{DBITS{1'bX}};
	
	// memory address is in resarith
	//wire [(DMEMADDRBITS-1):0] dmemaddr_A = resarith_A[(DMEMADDRBITS-1):0];
	wire [(DBITS-1):0] dmemaddr_A = resarith_A;
	
	// pcgood work
	wire iseq_A=(regval1_A==regval2_A);
	wire btake_A=
			btest_A &&
				((bcond_A==BCOND_EQ)?(iseq_A):
				(bcond_A==BCOND_NE)?(!iseq_A):
				1'bX);

	// A2M flip-flops
	reg selpcplus_M,selmem_M,selsreg_M,gotresALU_M,btake_M,isjump_M;
	reg wrmem_M,wsreg_M,reti_M,wrreg_M,iinst_M,sinst_M,flushed_M;
	reg [(DBITS-1):0] regval1_M,regval2_M,resALU_M,PC_M,btarg_M,jtarg_M,pcplus_M,pcpred_M;
	reg [(REGNOBITS-1):0] rregno1_M, wregno_M;
	reg [(DBITS-1):0] dmemaddr_M;
	always @(posedge clk) begin
		if(reset) begin
			flushed_M <= 1'b1;
			{btarg_M,jtarg_M,isjump_M,btake_M}<=
			{  32'b0,  32'b0,    1'b0,   1'b0};
		end
		{regval1_M,regval2_M,rregno1_M,wsreg_M,reti_M,wregno_M,wrreg_M}<=
		{regval1_A,regval2_A,rregno1_A,wsreg_A,reti_A,wregno_A,wrreg_A};
		{dmemaddr_M,wrmem_M,resALU_M,gotresALU_M}<=
		{dmemaddr_A,wrmem_A,result_A,gotresult_A};
		{selpcplus_M,selmem_M,selsreg_M}<=
		{selpcplus_A,selmem_A,selsreg_A};
		{iinst_M,sinst_M,flushed_M,PC_M,pcpred_M}<=
		{iinst_A,sinst_A,flushed_A,PC_A,pcpred_A};
		{btarg_M,jtarg_M,btake_M,isjump_M,pcplus_M}<=
		{btarg_A,jtarg_A,btake_A,isjump_A,pcplus_A};
		if(flush_A) begin
			{wrmem_M,wsreg_M,reti_M,wrreg_M,iinst_M,sinst_M,flushed_M}<=
			{   1'b0,   1'b0,  1'b0,   1'b0,   1'b0,   1'b0,     1'b1};
		end
	end

	/*-----------------------------
	 * MEMORY
	 *-----------------------------*/

	wire [(DBITS-1):0] wmemval_M = regval2_M;
	// create the bus
	wire [(DBITS-1):0] abus;
	tri [(DBITS-1):0] dbus;
	wire we;
	
	// HEX display
	reg [15:0] HexOut;
	wire [15:0] HexModuleOut;
	wire blink;
	always @(posedge clk)
		HexOut <= HexModuleOut;
	HexDisp #(.BITS(16), .ADDRDATA(ADDRHEX), .ADDRBLNK(ADDRHBLNK), .CLOCKS_PER_MS(CLOCKS_PER_MS)) HexDisp1(clk, lock, abus, dbus, we, HexModuleOut, blink);
	SevenSeg ss3(HEX3, HexOut[15:12], blink);
	SevenSeg ss2(HEX2, HexOut[11:8], blink);
	SevenSeg ss1(HEX1, HexOut[7:4], blink);
	SevenSeg ss0(HEX0, HexOut[3:0], blink);
			
	// LEDG and LEDR devices
	LED #(.BITS(10), .BASE(ADDRLEDR)) LED_red(clk, lock, abus, dbus, we, LEDRout);
	wire [9:0] LEDRout;
	assign LEDR = LEDRout;
	LED #(.BITS(8), .BASE(ADDRLEDG)) LED_green(clk, lock, abus, dbus, we, LEDGout);
	wire [7:0] LEDGout;
	assign LEDG = LEDGout;
	
	// Timer
	Timer #(.CLOCKS_PER_MS(CLOCKS_PER_MS)) T(clk, lock, abus, dbus, we);
	// Switches
	Switches #(.NUM(10), .ADDRCTRL(ADDRSCTRL), .ADDRDATA(ADDRSDATA), .CLOCKS_IN_10MS(CLOCKS_PER_10MS)) switches(clk, lock, abus, dbus, we, SW);
	// Keys
	Keys #(.NUM(4), .ADDRCTRL(ADDRKCTRL), .ADDRDATA(ADDRKDATA)) keys(clk, lock, abus, dbus, we, KEY);

	assign abus=dmemaddr_M;
	assign we=wrmem_M;
	assign dbus=wrmem_M?wmemval_M:{DBITS{1'bZ}};

	// Now the real data memory
	wire MemEnable=!(dmemaddr_M[(DBITS-1):DMEMADDRBITS]);
	wire MemWE=lock&wrmem_M&MemEnable;
	(* ramstyle="no_rw_check" *)
	reg [(DBITS-1):0] dmem[(DMEMWORDS-1):0];
	always @(posedge clk)
		if(MemWE)
			dmem[dmemaddr_M[(DMEMADDRBITS-1):DMEMWORDBITS]]<=wmemval_M;

	wire [(DBITS-1):0] MemVal=MemWE?{DBITS{1'bX}}:dmem[dmemaddr_M[(DMEMADDRBITS-1):DMEMWORDBITS]];
	wire [(DBITS-1):0] result_M =	selpcplus_M ? pcplus_M :
											gotresALU_M ? resALU_M :
											MemEnable ? MemVal :
											dbus;

	// determine mispred, pcgood
	// TODO: apparently there's a better way to do midpred (reference Processor Tour slide 20)
	wire [(DBITS-1):0] pcgood_M =
						btake_M ? btarg_M :
						isjump_M ? jtarg_M :
						pcplus_M;
	wire mispred_M = (pcgood_M!=pcpred_M) && !flushed_M;
	wire flush_M = mispred_M;
	
	// M2W flip-flops
	reg wrreg_W;
	reg [(REGNOBITS-1):0] wregno_W;
	reg [(DBITS-1):0] result_W;
	always @(posedge clk) begin
		if(lock) begin
			{wrreg_W,wregno_W,result_W}<=
			{wrreg_M,wregno_M,result_M};
		end
		else
			wrreg_W <= 1'b0;
	end

	/*-----------------------------
	 * WRITE REGISTERS
	 *-----------------------------*/

	// do the write if requested
	always @(posedge clk) begin
		if (wrreg_W)
			regs[wregno_W] <= result_W; //TODO how does pcplus get written back for JAL?
	end

endmodule